﻿/*
 * Copyright (C) 2023 - 2024 lchfj.cn
 * 
 * This file is part of FastestHost.
 * 
 * FastestHost is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
 * 
 * FastestHost is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License along with FastestHost. If not, see <https://www.gnu.org/licenses/>.
 */

using System.Collections.Concurrent;
using System.Collections.Immutable;
using System.Net;
using DnsClient;

namespace Cn.Lchfj.FastestHost
{
    internal class NslookupReader
    {
        internal static readonly ImmutableArray<string> sourceArray = ["1.2.4.8", "223.5.5.5", "180.76.76.76", "119.29.29.29", "114.114.114.114", "8.8.8.8", "208.67.222.222", "1.1.1.1"];

        private ImmutableArray<LookupClient> DnsClient;
        private readonly object LockerObject;

        internal NslookupReader()
        {
            var list = sourceArray.Select(ip => new LookupClient(IPAddress.Parse(ip)));
            DnsClient = [new(), .. list];
            LockerObject = new object();
        }

        public async Task<IReadOnlyList<string>> ReadAsync(string host)
        {
            var bags = new ConcurrentBag<string>();

            await Parallel.ForEachAsync(DnsClient, async (client, token) =>
            {
                try
                {
                    var ipList = await client.QueryAsync(host, QueryType.A, cancellationToken: token);
                    foreach (var ip in ipList?.Answers?.ARecords() ?? [])
                        bags.Add(ip.Address.ToString());


                    ipList = await client.QueryAsync(host, QueryType.AAAA, cancellationToken: token);
                    foreach (var ip in ipList?.Answers?.AaaaRecords() ?? [])
                        bags.Add(ip.Address.ToString());
                }
                catch
                {
                    lock (LockerObject)
                        DnsClient = DnsClient.Remove(client);
                }
            });

            return bags.Distinct(StringComparer.OrdinalIgnoreCase).ToImmutableArray();
        }
    }
}
